package com.rtmart.txd.barcode.print;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.krysalis.barcode4j.impl.code39.Code39Bean;
import org.krysalis.barcode4j.output.bitmap.BitmapCanvasProvider;
import org.krysalis.barcode4j.tools.UnitConv;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.print.*;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class WindowsPrint implements Printable {

    //每页打印条码的数量
    private static int PAGESIZE = 4;
    //每行打印几个条码
    private static int COUNTPERROW = 2;
    //打印每行占用的高度mm
    private static double HEIGHT = 130;

    //需要打印的条码
    private List<String> barCodeList = new ArrayList<>();

    public WindowsPrint() {
    }

    public WindowsPrint(List<String> barCodeList) {
        this.barCodeList = barCodeList;
    }

    public boolean print() {
        PrinterJob myPrtJob = PrinterJob.getPrinterJob(); // 获取默认打印作业
        PageFormat pageFormat = myPrtJob.defaultPage(); // 获取默认打印页面格式

        //设置成竖打
        pageFormat.setOrientation(PageFormat.PORTRAIT);
        //通过Paper设置页面的空白边距和可打印区域。必须与实际打印纸张大小相符。
        Paper pager = new Paper();
        pager.setSize(590, 840);//纸张大小
        pager.setImageableArea(72, 72, 535, 780);
        pageFormat.setPaper(pager);
        myPrtJob.setPrintable(this, pageFormat); // 设置打印工作
        if (myPrtJob.printDialog()) // 显示打印对话框
        {
            try {
                myPrtJob.print(); // 进行每一页的具体打印操作
            } catch (PrinterException pe) {
                pe.printStackTrace();
                return false;
            }
        } else return false;
        return true;
    }

    @Override
    public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
        /*Graphic 指明打印的图形环境；PageFormat 指明打印页格式（页面大小以点为计量单位，1 点为 1 英寸的 1/72，1 英寸为 25.4 毫米。A4 纸大致为 595 × 842 点）；page 指明页号 */

        if (page + 1 > (barCodeList.size() + PAGESIZE - 1) / PAGESIZE)
            return Printable.NO_SUCH_PAGE;// 当打印页号大于需要打印的总页数时，打印工作结束

        Graphics2D g2 = (Graphics2D) g;
        g2.setPaint(Color.black); // 设置打印颜色为黑色
        Paper paper = pf.getPaper();//得到页面格式的纸张
        paper.setSize(595, 840);//纸张大小
        paper.setImageableArea(72, 72, 535, 780); //设置打印区域的大小
        //System.out.println(paper.getWidth());
        //System.out.println(paper.getHeight());
        pf.setPaper(paper);//将该纸张作为格式 */
        g2.translate(pf.getImageableX(), pf.getImageableY());// 转换坐标，确定打印边界

        //printCode(g2, pf, page)//barcode4j打印的过程
        zxingPrintCode(g2, pf, page); //zxing打印的过程

        return Printable.PAGE_EXISTS; // 存在打印页时，继续打印工作
    }
    /**
    //barcode4j生成条码，宽高单位比较诡异没弄懂
    public void printCode(Graphics2D g2, PageFormat pf, int page) {

        String format = "image/png";

        //条码类型Code39
        Code39Bean bean = new Code39Bean();
        // 精细度
        final int dpi = 200;
        // module宽度
        //final double moduleWidth = UnitConv.in2mm(0.8f / dpi);
        bean.setModuleWidth(UnitConv.in2mm(1f / dpi));
        //bean.setHeight(UnitConv.in2mm(0.8f / dpi));
        //条码高度
        bean.setBarHeight(UnitConv.in2mm(200f / dpi));
        //bean.setBarHeight(25);
        //设置字号
        bean.setFontSize(3);
        bean.setWideFactor(2); //宽度因子
        //bean.doQuietZone(false);//不知都什么含义

        try {
            for (int i = 0; i < PAGESIZE && page * PAGESIZE + i < barCodeList.size(); i++) {
                //File file = new File("temp.png");

                //接收生成的条码 字节流
                ByteArrayOutputStream barcodeOS = new ByteArrayOutputStream();
                // 输出到流
                BitmapCanvasProvider canvas = new BitmapCanvasProvider(barcodeOS, format, dpi, BufferedImage.TYPE_BYTE_BINARY, false, 0);
                // 生成条形码
                bean.generateBarcode(canvas, barCodeList.get(page * PAGESIZE + i));
                // 结束绘制
                canvas.finish();

                //输出流转输入流
                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(barcodeOS.toByteArray());
                //输入流转图片
                Image bufferedImage = ImageIO.read(byteArrayInputStream);
                //在画布上输出条码图片
                g2.drawImage(bufferedImage, i % COUNTPERROW * 260, (int) (i / COUNTPERROW * HEIGHT / 25.4 * 72), null);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
**/
    //Zxing 生成条码，文字需要自己输出，文字比barcode4j的美观
    public void zxingPrintCode(Graphics2D g2, PageFormat pf, int page) {
        int codeWidth = 200;
        int height = 200;//单位貌似是寸，1 = 0.3mm

        //配置参数
        Map<EncodeHintType,Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        // 容错级别 这里选择最高H级别
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        Font font=new Font("Serif",Font.PLAIN, 18);//衬线字体
        g2.setFont(font);
        for (int i = 0; i < PAGESIZE && page * PAGESIZE + i < barCodeList.size(); i++) {
            try {
                String content = barCodeList.get(page * PAGESIZE + i);//条码内容
                BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.CODE_128, codeWidth, height, hints);//生成条码矩阵
                BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);//转换为图片

                int x = i % COUNTPERROW * 260, y = (int) (i / COUNTPERROW * HEIGHT / 25.4 * 72);//计算坐标
                g2.drawImage(bufferedImage, x, y, null);//输出条码

                FontMetrics m = g2.getFontMetrics();
                int contentWidth = m.stringWidth(content);//文字内容宽度
                g2.drawString(content,x+(bufferedImage.getWidth()-contentWidth)/2f,y + height + 20);//输出文字
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    }
}
